home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / teco / part04 < prev    next >
Encoding:
Internet Message Format  |  1987-03-11  |  34.4 KB

  1. Subject:  v09i031:  A TECO text editor, Part04/04
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: genrad!mlf
  6. Mod.sources: Volume 9, Issue 31
  7. Archive-name: teco/Part04
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If this archive is complete, you will see the message:
  13. #        "End of archive 4 (of 4)."
  14. # Contents:  te_window.c
  15. # Wrapped by rs@mirror on Thu Mar 12 19:54:35 1987
  16. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  17. echo shar: Extracting \"te_window.c\" \(33018 characters\)
  18. if test -f te_window.c ; then 
  19.   echo shar: Will not over-write existing file \"te_window.c\"
  20. else
  21. sed "s/^X//" >te_window.c <<'END_OF_te_window.c'
  22. X/* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum                        */
  23. X/* This program and its components belong to GenRad Inc, Concord MA 01742    */
  24. X/* They may be copied if this copyright notice is included                    */
  25. X
  26. X/* te_window.c   window for teco   10/10/86 */
  27. X/* This attempts to be a real window, without unecessary redraw */
  28. X/* it is very VT-100 specific, and ought to be rewritten to be general */
  29. X
  30. X#include "te_defs.h"
  31. X
  32. X/* maximum screen height and width (horiz and vert, not height and vidth) */
  33. X#define W_MAX_V 70
  34. X#define W_MAX_H 150
  35. X#define MAX 0x7fffffff            /* maximum positive integer, for "last modified" location */
  36. X#define W_MARK 0200                /* "this loc is special" in screen image */
  37. X
  38. X
  39. X/* image of current window */
  40. X
  41. Xstruct w_line            /* data associated with one screen line */
  42. X    {
  43. X    int start, end;                /* dot at beginning, at end */
  44. X    short n, cflag, col;        /* number of char positions used, line continuation flag, starting col */
  45. X    char ch[W_MAX_H];            /* image of line */
  46. X    }
  47. X     w_image[W_MAX_V];
  48. X
  49. X
  50. X/* define "this line is continued" / "this line is a continuation" flags */
  51. X#define WF_BEG 1
  52. X#define WF_CONT 2
  53. X
  54. Xstruct w_line *wlp[W_MAX_V];    /* each word points to the corresponding line's data structure */
  55. X
  56. Xstruct qp w_p1;                    /* pointer for window access to buffer */
  57. X
  58. Xshort curr_x, curr_y;            /* active character position */
  59. Xshort term_x, term_y;            /* current terminal cursor position */
  60. Xshort curs_x, curs_y;            /* current teco dot screen coordinates */
  61. Xshort last_y;                    /* last used line in window */
  62. Xchar curs_c;                    /* code for char at cursor */
  63. Xchar *curs_p;                    /* pointer to cursor loc in window image */
  64. Xshort curs_crflag;                /* flag that cursor is on a CR */
  65. Xshort redraw_sw;                /* forces absolute redraw */
  66. X
  67. X
  68. X/* fill characters and terminal speeds: 0th entry used when std out is not a terminal */
  69. Xchar win_speeds[] = { 0, 0, B9600, B4800, B2400, B1800, B1200, B600, B300, B200, B150, B134, B110 };
  70. Xchar win_dlye[] =   { 0, 90, 45, 23, 11, 9, 6, 3, 1, 1, 1, 1, 1 };    /* delay for erase-screen */
  71. Xchar win_dlys[] =   { 0, 60, 30, 15, 7, 6, 4, 2, 1, 1, 0, 0, 0 };    /* delay for scroll ops */
  72. Xchar win_dlyl[] =   { 0, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };        /* delay for erase line */
  73. Xchar win_dlyc[] =   { 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };        /* delay for other control functions */
  74. Xshort win_speed;
  75. X /* routine to perform simple scope operations */
  76. X/* (an attempt to concentrate VT-100 specific things in one place) */
  77. X
  78. Xvt(func)
  79. X    int func;
  80. X    {
  81. X    short t;
  82. X    switch (func)
  83. X        {
  84. X        case VT_CLEAR:            /* clear screen */
  85. X            fputs("\033[H\033[J", stdout);
  86. X            for (t = 0; t < win_dlye[win_speed]; t++) putchar('\0');    /* fill chars */
  87. X            break;
  88. X
  89. X        case VT_EEOL:            /* erase to end of line */
  90. X            fputs("\033[K", stdout);
  91. X            for (t = 0; t < win_dlyl[win_speed]; t++) putchar('\0');    /* fill chars */
  92. X            break;
  93. X
  94. X        case VT_EBOL:            /* erase from beginning of line */
  95. X            fputs("\033[1K", stdout);
  96. X            for (t = 0; t < win_dlyl[win_speed]; t++) putchar('\0');    /* fill chars */
  97. X            break;
  98. X
  99. X        case VT_SETSPEC1:        /* reverse video */
  100. X            fputs("\033[7m", stdout);
  101. X            break;
  102. X
  103. X        case VT_SETSPEC2:        /* bright reverse video */
  104. X            fputs("\033[1;7m", stdout);
  105. X            break;
  106. X
  107. X        case VT_CLRSPEC:        /* normal video */
  108. X            fputs("\033[0m", stdout);
  109. X            break;
  110. X
  111. X        case VT_BS1:            /* backspace 1 spot */
  112. X            fputs("\b \b", stdout);
  113. X            break;
  114. X
  115. X        case VT_BS2:            /* backspace 2 spots */
  116. X            fputs("\b \b\b \b", stdout);
  117. X            break;
  118. X
  119. X        case VT_LINEUP:            /* up one line */
  120. X            fputs("\033[1A", stdout);
  121. X            break;
  122. X        }
  123. X    }
  124. X /* routine to set window parameters */
  125. X
  126. X/* 0: scope type, 1: width, 2: height, 3: seeall, 4: mark position,        */
  127. X/* 5: hold mode, 6: upper left corner position, 7: scroll region size    */
  128. X
  129. X/*                   0   1        2         3  4      5   6       7    */
  130. Xint win_min[]  = { 4,  20,        4,         0, 0,     -1,  1,   0 } ;    /* min values for window parameters */
  131. Xint win_max[]  = { 4,  W_MAX_H,    W_MAX_V, 1, MAX, 12, -1,  20 } ;    /* max values */
  132. Xint win_data[] = { 4,  132,        24,         0, 0,      0,  0,   0 } ;    /* window parameters    */
  133. X
  134. Xint window_size;                                /* # of lines in a window */
  135. X
  136. Xdo_window(ref_flag)
  137. X    int ref_flag;                    /* nonzero forces "refresh" operation */
  138. X    {
  139. X    int i;
  140. X
  141. X    if (colonflag && !ref_flag)
  142. X        {
  143. X        i = get_value(0);    /* get sub-function */
  144. X        if ((i < 0) || (i > 7)) ERROR(E_IWA);
  145. X        if (!esp->flag2)    /* it's a "get" */
  146. X            {
  147. X            esp->val1 = win_data[i];
  148. X            esp->flag1 = 1;
  149. X            }
  150. X        else
  151. X            {
  152. X            if ((esp->val2 < win_min[i]) || (esp->val2 > win_max[i]))    /* check range */
  153. X                ERROR(E_IWA);
  154. X            if (i == 7)
  155. X                {
  156. X                if (esp->val2)
  157. X                    {
  158. X                    WN_scroll = esp->val2;
  159. X                    window_size = WN_height - WN_scroll;    /* define size of window area */
  160. X                    window(WIN_INIT);            /* turn on window */
  161. X                    }
  162. X                else window(WIN_OFF);            /* turn off window */
  163. X                }
  164. X            win_data[i] = esp->val2;            /* redundant for ~0,7:w, but no harm */
  165. X            esp->flag2 = 0;
  166. X            window(WIN_REDRAW);                    /* redraw window */
  167. X            }
  168. X        }
  169. X
  170. X    else                                /* no colon, or ^W command */
  171. X        {
  172. X        if (esp->flag1 || ref_flag)
  173. X            {
  174. X            if (!ref_flag && (esp->val1 == -1000)) redraw_sw = 0;    /* -1000W: "forget that output was done" */
  175. X            else window(WIN_DISP);        /* nW or ^W refreshes window */
  176. X            }
  177. X         esp->flag2 = esp->flag1 = 0;        /* no colon, consume args */
  178. X        }
  179. X    colonflag = 0;
  180. X    esp->op = OP_START;
  181. X    }
  182. X /* routine to update screen size with numbers obtained from environment    */
  183. X/* (called by main program's initialization)                            */
  184. X
  185. Xset_term_par(lines, cols)
  186. X    int lines, cols;
  187. X    {
  188. X    if ((lines >= win_min[2]) && (lines <= win_max[2])) window_size = win_data[2] = lines;
  189. X    if ((cols >= win_min[1]) && (cols <= win_max[1])) win_data[1] = cols;
  190. X    }
  191. X
  192. X
  193. X/* window routine.  performs function as indicated by argument                        */
  194. X/* WIN_OFF:        disables split-screen scrolling                                        */
  195. X/* WIN_SUSP:    disables split-screen scrolling temporarily                            */
  196. X/* WIN_INIT:    sets up display support if split-screen scrolling enabled, else nop    */
  197. X/* WIN_RESUME:    re-enables display support                                            */
  198. X/* WIN_REDRAW:    causes window to be redrawn on next refresh call                    */
  199. X/* WIN_REFR:    if scrolling enabled, redoes window, else if ev or es enabled, does    */
  200. X/*                that, else nop                                                        */
  201. X/* WIN_LINE:    does WIN_REFR unless that wouldn't do anything, in which case        */
  202. X/*                it does effective 1EV output                                        */
  203. X
  204. Xint last_dot = -1;                /* last dot location */
  205. X
  206. Xwindow(arg)
  207. X    int arg;
  208. X    {
  209. X    int i;
  210. X
  211. X    switch (arg)
  212. X        {
  213. X        case WIN_OFF:                /* final window off */
  214. X        case WIN_SUSP:                /* temp window off */
  215. X            if (WN_scroll)            /* if reset/clean up */
  216. X                {
  217. X                /* full margins, cursor to last line, erase line */
  218. X                printf("\033[r\033[%d;0H\033[K", WN_height);
  219. X                }
  220. X            break;
  221. X
  222. X        case WIN_INIT:                /* initialize window - find output speed */
  223. X            if (out_noterm) win_speed = 0;        /* std out is not a terminal */
  224. X            else
  225. X                {
  226. X                for (win_speed = 1; (win_speeds[win_speed] != ttybuf.sg_ospeed) && (win_speed < 13); win_speed++);
  227. X                if (win_speed == 13) win_speed = 1;
  228. X                }
  229. X            w_init();                /* set up screen image buffer */
  230. X            if (WN_scroll) vt(VT_CLEAR);        /* if split-screen is enabled, clear screen */
  231. X                                    /* (fall through to "resume") */
  232. X
  233. X        case WIN_RESUME:            /* re-enable window */
  234. X            if (WN_scroll)            /* set scroll region, cursor to bottom */
  235. X                printf("\033[%d;%dr\033[%d;0H", WN_height - WN_scroll + 1, WN_height, WN_height);
  236. X            break;
  237. X         case WIN_REDRAW:        /* force redraw of window */
  238. X            redraw_sw = 1;
  239. X            break;
  240. X
  241. X        case WIN_LINE:            /* display one line unless window enabled or ev */
  242. X            if (WN_scroll || ev_val) window(WIN_REFR);        /* if a real window is set, do it */
  243. X            else if (w_setptr(dot, &w_p1))        /* set pointer to dot... and if there's a buffer */
  244. X                {
  245. X                w_lines(0, &w_p1, &w_p1);        /* get to beginning of line */
  246. X                window0(1);                        /* and type 1 line */
  247. X                }
  248. X            break;
  249. X
  250. X        case WIN_REFR:            /* if enabled, refresh window; else do ev or es */
  251. X            if (WN_scroll) window1();        /* if scrolling enabled, refresh the window */
  252. X            else if ((ev_val) || (es_val && search_flag))    /* else if ev or es, do that */
  253. X                {
  254. X                i = (ev_val) ? ev_val : es_val;
  255. X                if (w_setptr(dot, &w_p1))        /* set a pointer at dot... and if there's a buffer */
  256. X                    window0(i - w_lines(1 - i, &w_p1, &w_p1));    /* go back (i-1) lines and ahead (i) lines */
  257. X                }
  258. X            break;
  259. X
  260. X        case WIN_DISP:                    /* display buffer independent of whether scroll mode is enabled */
  261. X            window1();
  262. X            break;
  263. X
  264. X        }        /* end of switch */
  265. X
  266. X    fflush(stdout);            /* send output out */
  267. X    }                    /* end of window() */
  268. X /* routine to type n lines with character at "dot" in reverse video            */
  269. X/* used for ev, es, and <BS> or <LF> as immediate commands                    */
  270. X/* starting char position is in w_p1; argument is number of lines            */
  271. X
  272. Xwindow0(num)
  273. X    int num;
  274. X    {
  275. X    int wi;
  276. X    char wc;            /* temp char */
  277. X
  278. X    for (wi = w_p1.dot; (num > 0) && (wi < z); wi++)        /* for each character */
  279. X        {
  280. X        wc = w_p1.p->ch[w_p1.c];        /* get character */
  281. X
  282. X        if ((char_count >= WN_width) && (wc != CR) && !(spec_chars[wc] & A_L))    /* if about to exceed width */
  283. X            {
  284. X            if (et_val & ET_TRUNC) goto w0_noprint;            /* truncate: don't print this */
  285. X            else
  286. X                {
  287. X                fputs("\033[K\015\012\033(0h\033(B ", stdout);    /* <eeol> "NL space" */
  288. X                char_count = 2;
  289. X                --num;                    /* one fewer line remaining */
  290. X                }
  291. X            }
  292. X
  293. X        if (wi == dot)                    /* if this char is at the pointer */
  294. X            {
  295. X            vt(VT_SETSPEC2);            /* set reverse video */
  296. X            if (wc == TAB)
  297. X                {
  298. X                type_char(' ');        /* illuminate the first sp of a tab */
  299. X                vt(VT_CLRSPEC);        /* clear reverse video */
  300. X                if (char_count & tabmask) type_char(TAB);
  301. X                }
  302. X            else                        /* not a tab */
  303. X                {
  304. X                if ((wc == CR) && (char_count < WN_width))    /* CR at rh margin: don't display cursor */
  305. X                    {
  306. X                    type_char(' ');        /* cr: put a space after line */
  307. X                    vt(VT_EEOL);        /* erase to eol */
  308. X                    }
  309. X                type_char(wc);            /* type the char, or exec CR */
  310. X                if (wc == LF)
  311. X                    {
  312. X                    fputs("\033(0", stdout);
  313. X                    type_char('e');
  314. X                    fputs("\033(B", stdout);
  315. X                    }
  316. X                vt(VT_CLRSPEC);        /* clear reverse video */
  317. X                }
  318. X            }
  319. X         else                    /* this is not char at pointer */
  320. X            {
  321. X            if (wc == CR && curr_x < WN_width) vt(VT_EEOL);        /* erase to EOL */
  322. X            type_char(wc);
  323. X            }
  324. X        if ((wc == FF) || (wc == VT))        /* FF & VT end a line */
  325. X            {
  326. X            vt(VT_EEOL);            /* erase rest of this line */
  327. X            crlf();                    /* and leave a blank one */
  328. X            if (!(ez_val & EZ_NOVTFF)) --num;        /* if FF and VT count as line sep's, count them */
  329. X            }
  330. X
  331. X      w0_noprint:
  332. X        if (++w_p1.c > CELLSIZE-1) w_p1.p = w_p1.p->f, w_p1.c = 0;    /* next char */
  333. X        if (wc == LF) --num;    /* if this is a line feed, count lines */
  334. X        }
  335. X
  336. X    if (dot == z) fputs("\033[1;7m \033[0m\033[0K", stdout);    /* type one space and erase rest of line */
  337. X    else fputs("\033[0K", stdout);            /* else just erase to EOL */
  338. X    }
  339. X /* routine to maintain the screen window                                        */
  340. X/* if scroll mode is enabled, the VT100 screen is split and only the upper part */
  341. X/* is used by this routine; else the whole screen is used.                        */
  342. X
  343. Xwindow1()
  344. X    {
  345. X    int i, j, m, lflag;
  346. X
  347. X    if (!redraw_sw && (dot == last_dot) && (buff_mod == MAX)) return;        /* return if nothing has changed */
  348. X
  349. X    block_inter(1);                            /* disable ^C interrupts */
  350. X    if (WN_scroll) printf("\033[1;%dr", window_size);        /* scroll mode: redefine scroll region */
  351. X    printf("\033[H");                        /* home */
  352. X    term_y = term_x = 0;                    /* indicate cursor is at home */
  353. X
  354. X    if ((redraw_sw) || (z <= wlp[0]->start)) window1_abs();        /* forced redraw, or z before start of screen */
  355. X
  356. X
  357. X/* check whether pointer is before modified buffer location */
  358. X
  359. X    else if (buff_mod >= dot)    /* yes */
  360. X        {
  361. X
  362. X        if (dot < wlp[0]->start)            /* if dot is before screen */
  363. X            {
  364. X            w_setptr(wlp[0]->start, &w_p1);    /* get to beginning of screen */
  365. X
  366. X        /* check whether screen begins with the last part of a continued line */
  367. X            for (j = 0; (wlp[j]->cflag & WF_CONT) && (j < window_size/2); j++);
  368. X            if (j < window_size/2)            /* if so, does it continue less than halfway down the screen? */
  369. X                {
  370. X
  371. X                if (j)                        /* is there a partial line? */
  372. X                    {
  373. X                    w_lines(0, &w_p1, &w_p1);        /* 0L */
  374. X                    j -= w_lines(1, &w_p1, NULL);        /* now j is number of display lines before screen */
  375. X                    }
  376. X         /* now look for how many lines back "dot" is: if screen starts with partial line, w_p1 has already been moved */
  377. X        /* to beginning of the line and j equals the count of extra lines to scroll */
  378. X
  379. X                for (i = 0; (dot < w_p1.dot) && (i < window_size/2); ) i -= w_lines(-1, &w_p1, &w_p1);
  380. X                if ((dot >= w_p1.dot) && (i < window_size))            /* found point within reason */
  381. X                    {
  382. X                    w_scroll(j - i);            /* scroll screen down that many lines */
  383. X                    curr_y = wlp[0]->cflag = wlp[0]->col = curr_x = 0;        /* start from top of screen */
  384. X                    wlp[0]->start = w_p1.dot;    /* save starting char position */
  385. X                    window2(0);                    /* and rewrite screen */
  386. X                    }
  387. X
  388. X                else window1_abs();                /* farther back than that - redraw */
  389. X                }
  390. X
  391. X            else window1_abs();                    /* continuation was too long: give up and redraw */
  392. X            }                /* end of "dot is before screen" */
  393. X
  394. X        else if (dot <= wlp[last_y]->end) window1_inc(dot);        /* on screen - redraw incrementally */
  395. X
  396. X        else window1_after();                /* dot is after screen: scroll or redraw */
  397. X        }                /* end of "dot is before modified point" */
  398. X
  399. X
  400. X/* the modified point in the buffer is before dot */
  401. X
  402. X    else
  403. X        {
  404. X        if (buff_mod < wlp[0]->start) window1_abs();    /* modified point before screen - redraw fully */
  405. X
  406. X        else if (buff_mod <= wlp[last_y]->end)            /* modified point on screen */
  407. X            {
  408. X            for (m = 0; buff_mod > wlp[m]->end; m++);    /* find line with buff_mod */
  409. X            w_setptr(wlp[m]->start, &w_p1);                /* set a pointer to start of line with buff_mod */
  410. X            j = (m < window_size/2) ? window_size - 1 - m : window_size/2;    /* maximum # of lines between buff_mod & dot */
  411. X            for (i = 0; (dot >= w_p1.dot) && (w_p1.dot < z) && (i <= j); )
  412. X                i += (lflag = w_lines(1, &w_p1, &w_p1) ) ? lflag : 1;    /* count lines from buff_mod to first line after dot */
  413. X            if (i > j) window1_abs();                    /* too far - redraw */
  414. X            else
  415. X                {
  416. X                if (lflag && (dot == z)) i++;            /* if at end, following a LF */
  417. X                w_setptr(wlp[m]->start, &w_p1);            /* pointer to start of area to redraw */
  418. X                if (i >= window_size - m)                /* if there are not enough blank lines on screen */
  419. X                    w_scroll(i = i - window_size + m), curr_y = m - i, curs_y -= i;    /* scroll up the difference */
  420. X                else curr_y = m;
  421. X                curr_x = (wlp[curr_y]->cflag & WF_CONT) ? 2 : wlp[curr_y]->col;        /* line starts at left unless continuation */
  422. X                if ((curr_y > curs_y) && (curs_y >= 0)) w_rmcurs();        /* remove old cursor if it won't be written over */
  423. X                window2(0);                            /* rewrite newly cleared region */
  424. X                for (curr_x = 0; ++curr_y < window_size; )        /* clear rest of screen if needed */
  425. X                    {
  426. X                    wlp[curr_y]->cflag = 0;
  427. X                    if (wlp[curr_y]->n) wlp[curr_y]->n = 0, vtm(VT_EEOL);
  428. X                    }
  429. X                }
  430. X            }            /* end "modified point on screen */
  431. X
  432. X        else window1_after();        /* modified point after screen: scroll or redraw as appropriate */
  433. X        }
  434. X /* done redrawing: do cleanup work */
  435. X
  436. X    if (WN_scroll)
  437. X        {
  438. X        printf("\033[%d;%dr", window_size+1, WN_height);    /* reset margins */
  439. X        printf("\033[%d;0H", WN_height);        /* cursor to bottom */
  440. X        }
  441. X    else printf("\033[H");        /* no split screen: set home */
  442. X
  443. X    fflush(stdout);                /* flush output */
  444. X    WN_origin = wlp[0]->start;    /* save first char pos on screen */
  445. X    redraw_sw = 0;                /* mark screen as updated */
  446. X    buff_mod = MAX;
  447. X    last_dot = dot;
  448. X    block_inter(0);                /* reenable interrupts */
  449. X    }
  450. X /* routine to redraw screen absolutely */
  451. X
  452. Xwindow1_abs()
  453. X    {
  454. X    int i, j;
  455. X
  456. X    curr_y = wlp[0]->col = curr_x = 0;                /* indicate where refresh starts */
  457. X    set_pointer(dot, &w_p1);                        /* make a text buffer, if none, and refresh the display */
  458. X    w_lines(0, &w_p1, &w_p1);                        /* do 0L */
  459. X    if ((i = w_lines(window_size/2, &w_p1, NULL)) == 0) i = 1;        /* check how many lines after dot */
  460. X    if (i > window_size/2) i = window_size/2;        /* limit amount after dot */
  461. X    for (j = 0; (j < window_size - i) && (w_p1.dot > 0); )        /* find start of display area */
  462. X        j -= w_lines(-1, &w_p1, &w_p1);
  463. X    if (j > window_size - i) w_lines(1, &w_p1, &w_p1);            /* if too far back, move up one line */
  464. X
  465. X    wlp[0]->start = w_p1.dot;        /* indicate where first window line starts */
  466. X    window2(0);                        /* refresh the whole display */
  467. X
  468. X    for (curr_x = 0; ++curr_y < window_size; )        /* blank out lines not written by window2 */
  469. X        if (wlp[curr_y]->n || redraw_sw) wlp[curr_y]->n = 0, vtm(VT_EEOL);
  470. X    }
  471. X
  472. X
  473. X
  474. X
  475. X/* redraw screen incrementally */
  476. X
  477. Xwindow1_inc(wd)
  478. X    int wd;                        /* argument is earliest change */
  479. X    {
  480. X    short temp_y;
  481. X
  482. X/* find the line containing the character at wd */
  483. X
  484. X    for (temp_y = 0; wd > wlp[temp_y]->end; temp_y++);
  485. X
  486. X    if ((curs_y != temp_y) || (buff_mod == MAX) || curs_crflag)        /* if the cursor line won't be rewritten */
  487. X        w_rmcurs();                    /* remove the old cursor */
  488. X    curr_y = temp_y;                /* and go to work on the beginning of the line with dot */
  489. X    curr_x = (wlp[curr_y]->cflag & WF_CONT) ? 2 : wlp[curr_y]->col;        /* line starts at left unless continuation */
  490. X
  491. X    w_setptr(wlp[curr_y]->start, &w_p1);        /* make a pointer there */
  492. X    window2(buff_mod == MAX);        /* if buffer not modified, redraw only the line with dot */
  493. X
  494. X    if (buff_mod < MAX)            /* if buffer has changed, erase display lines beyond end of buffer */
  495. X        for (curr_x = 0; ++curr_y < window_size; )
  496. X            if ( ((wlp[curr_y]->start >= z) || (wlp[curr_y]->start <= wlp[curr_y-1]->end)) && (wlp[curr_y]->n || redraw_sw) )
  497. X                wlp[curr_y]->n = 0, vtm(VT_EEOL), wlp[curr_y]->cflag = 0;
  498. X    }
  499. X /* routine to move window downwards: scroll up or redraw as appropriate */
  500. X
  501. Xwindow1_after()
  502. X    {
  503. X    int i, lflag;
  504. X
  505. X    w_rmcurs();                        /* remove old cursor */
  506. X    w_setptr(wlp[window_size-1]->start, &w_p1);        /* set pointer to start of last line on screen */
  507. X
  508. X    for (i = 0; (dot >= w_p1.dot) && (w_p1.dot < z) && (i <= window_size/2); )
  509. X        i += (lflag = w_lines(1, &w_p1, &w_p1)) ? lflag : 1;    /* fwd one line at a time until > dot or end of buffer */
  510. X
  511. X    if (i <= window_size/2)            /* found within n lines */
  512. X        {
  513. X        if (lflag && (dot == z)) ++i;                /* if dot is at end of buffer after a LF */
  514. X        if (i >= window_size - last_y)                /* if there are not enough blank lines on screen */
  515. X            w_scroll(i - window_size + last_y), curr_y = window_size - i;    /* scroll up the difference */
  516. X        else curr_y = last_y;
  517. X
  518. X        while (curr_y && (wlp[curr_y]->cflag & WF_CONT)) --curr_y;        /* get to start of cont'd lines */
  519. X        w_setptr(wlp[curr_y]->start, &w_p1);        /* pointer to start of area to redraw */
  520. X        curr_x = wlp[curr_y]->col;                    /* redraw starts at line's first column */
  521. X        window2(0);                                    /* rewrite newly cleared region */
  522. X        }
  523. X
  524. X    else window1_abs();                        /* move down is too far: redraw fully */
  525. X    }
  526. X
  527. X
  528. X
  529. X/* routine to remove the existing cursor */
  530. X
  531. Xw_rmcurs()
  532. X    {
  533. X    if (curs_c)            /* if there was a cursor */
  534. X        {
  535. X        w_move(curs_y, curs_x);        /* go remove the old cursor */
  536. X        if (curs_c & W_MARK) fputs("\033(0", stdout);        /* if prev char was a spec char */
  537. X        putchar(*curs_p = curs_c);    /* put back the char that was there */
  538. X        if (curs_c & W_MARK) fputs("\033(B", stdout);
  539. X        ++term_x;                    /* and keep the terminal cursor loc. happy */
  540. X        }
  541. X    }
  542. X /* routine to do actual display refresh                                                */
  543. X/* called with w_p1 at starting char, curr_y, curr_x at starting coordinate            */
  544. X/* rewrites to end of screen if arg = 0, or only until line with cursor if arg = 1    */
  545. X
  546. Xwindow2(arg)
  547. X    int arg;
  548. X    {
  549. X    register int wdot;
  550. X    register char wc;            /* temp char */
  551. X    register short dflag;        /* nonzero if this is char at dot */
  552. X    short cr_found;                /* indicates a cr found on this line */
  553. X
  554. X    cr_found = 0;                /* clear "cr" flag in first line written */
  555. X    for (wdot = w_p1.dot; (curr_y < window_size) && (wdot < z); wdot++)        /* for each character */
  556. X        {
  557. X        wc = w_p1.p->ch[w_p1.c] & 0177;        /* get character */
  558. X        if (dflag = (wdot == dot)) if (arg) arg = -1;        /* save "this is char at dot", "on line with dot" */
  559. X
  560. X        if (wc < ' ') switch (wc)                /* dispatch control characters */
  561. X            {
  562. X            case CR:
  563. X                if (dflag)            /* if cursor on this CR */
  564. X                    {
  565. X                    if (curr_x < WN_width) w_makecurs(' ', 1), w_type(' ', 1);    /* display a space, unless at end */
  566. X                    else curs_crflag = curs_c = 0;                /* else set "no cursor displayed" */
  567. X                    }
  568. X                /* trim remainder of line if this is first cr and old line was longer */
  569. X                if (!cr_found && ((curr_x < wlp[curr_y]->n) || redraw_sw))
  570. X                    {
  571. X                    wlp[curr_y]->n = curr_x;
  572. X                    if (curr_x < WN_width) vtm(VT_EEOL);
  573. X                    }
  574. X                cr_found = 1;            /* set cr flag */
  575. X                wlp[curr_y]->cflag &= ~WF_BEG;        /* this line is not continued */
  576. X                while (curr_y && (wlp[curr_y]->cflag & WF_CONT)) --curr_y;        /* if line is a continuation, scan up */
  577. X                curr_x = 0;
  578. X                break;
  579. X
  580. X            case TAB:
  581. X                if (curr_x >= WN_width)
  582. X                    {
  583. X                    if (et_val & ET_TRUNC) goto noprint;
  584. X                    if (w_overflow(wdot)) goto w2_exit;                /* extend line */
  585. X                    }
  586. X                if (dflag) w_makecurs(' ', 0);
  587. X                w_type(' ', dflag);                        /* type one space */
  588. X                if (dflag)
  589. X                    {
  590. X                    vt(VT_CLRSPEC);        /* end reverse video */
  591. X                    dflag = 0;
  592. X                    }
  593. X                while ((curr_x & tabmask) && (curr_x < WN_width)) w_type(' ', 0);        /* finish tab */
  594. X                break;
  595. X             case LF:
  596. X                while ((curr_y < window_size) && (wlp[curr_y]->cflag & WF_BEG)) ++curr_y;    /* last screen row of this line */
  597. X                wlp[curr_y]->end = wdot;        /* save char position that ended this line */
  598. X                if (dflag)        /* if this LF is at dot */
  599. X                    {            /* put cursor there, save char that was there */
  600. X                    w_makecurs( (curr_x < wlp[curr_y]->n) ? wlp[curr_y]->ch[curr_x] : ' ', 0);
  601. X                    fputs("\033(0", stdout);            /* put in a "LF" char */
  602. X                    w_type('e', 1);
  603. X                    fputs("\033(B", stdout);
  604. X                    }            /* if no cr found and not in last column, erase rest of line */
  605. X                if (!cr_found && (curr_x < wlp[curr_y]->n))
  606. X                    {
  607. X                    wlp[curr_y]->n = curr_x;
  608. X                    if (curr_x < WN_width) vtm(VT_EEOL);
  609. X                    }
  610. X                if (dflag) --curr_x;            /* put the cursor back before the artificial LF char, if any */
  611. X                if (curr_y >= window_size-1)    /* if at end of screen, exit, but... */
  612. X                    {
  613. X                    if (dflag) vt(VT_CLRSPEC);    /* if cursor is here, clear reverse video first */
  614. X                    goto w2_exit;
  615. X                    }
  616. X
  617. X                if ((wlp[curr_y]->cflag & WF_CONT) && (wlp[curr_y]->end - wlp[curr_y]->start == 1))    /* if a now-empty cont. line, */
  618. X                    {                                                            /* flush it */
  619. X                    if (curr_y > 0) wlp[curr_y-1]->cflag &= ~WF_BEG;            /* remove "cont'd" flag from prev line */
  620. X                    arg = 0;                                                    /* and force redraw of rest of screen */
  621. X                    if (curs_y == curr_y) curs_c = 0;                            /* if cursor was on this line, it will disappear */
  622. X                    }
  623. X                else ++curr_y;                /* down one line if not absorbing blank contin. line */
  624. X
  625. X                wlp[curr_y]->start = wdot + 1;                /* assume line starts with next char */
  626. X                wlp[curr_y]->col = curr_x;                    /* save starting column */
  627. X                cr_found = wlp[curr_y]->cflag = 0;            /* clear line continuation flags */
  628. X                if (curr_x) w_ebol();                        /* if not at left margin, erase beginning of line */
  629. X                if (arg == -1)                                /* finished line with dot... quit if spec'd */
  630. X                    {
  631. X                    if (dflag)                        /* but first, if at cursor, clear reverse video */
  632. X                        {
  633. X                        vt(VT_CLRSPEC);
  634. X                        dflag = 0;
  635. X                        }
  636. X                    return;
  637. X                    }
  638. X                break;
  639. X
  640. X            case ESC:
  641. X                if (curr_x >= WN_width)
  642. X                    {
  643. X                    if (et_val & ET_TRUNC) goto noprint;
  644. X                    if (w_overflow(wdot)) goto w2_exit;                /* extend line */
  645. X                    }
  646. X                if (dflag) w_makecurs('$', 0);
  647. X                w_type('$', dflag);
  648. X                break;
  649. X             default:                    /* all other control chars print as ^X */
  650. X                if (curr_x >= WN_width - 1)
  651. X                    {
  652. X                    if (et_val & ET_TRUNC) goto noprint;
  653. X                    if (w_overflow(wdot)) goto w2_exit;
  654. X                    }
  655. X                if (dflag) w_makecurs('^', 0);
  656. X                w_type('^', dflag);                /* ^ */
  657. X                if (dflag)
  658. X                    {
  659. X                    vt(VT_CLRSPEC);        /* if at cursor, clear reverse video */
  660. X                    dflag = 0;
  661. X                    }
  662. X                w_type(wc | 0100, 0);
  663. X                break;
  664. X            }                    /* end "switch" */
  665. X        else                    /* a printing character */
  666. X            {
  667. X            if (curr_x >= WN_width)
  668. X                {
  669. X                if (et_val & ET_TRUNC) goto noprint;
  670. X                if (w_overflow(wdot)) goto w2_exit;                /* extend line */
  671. X                }
  672. X            if (dflag) w_makecurs(wc, 0);
  673. X            w_type(wc, dflag);
  674. X            }
  675. X
  676. X        if (dflag)
  677. X            {
  678. X            vt(VT_CLRSPEC);                /* if at cursor, clear reverse video */
  679. X            }
  680. X
  681. X        if ((wc == FF) || (wc == VT))            /* these chars leave a display line blank */
  682. X            {
  683. X            if (redraw_sw || (curr_x < wlp[curr_y]->n))
  684. X                {
  685. X                wlp[curr_y]->n = curr_x;
  686. X                if (curr_x < WN_width) vtm(VT_EEOL);    /* erase rest of line */
  687. X                }
  688. X            wlp[curr_y]->end = wdot;
  689. X            if (curr_y >= window_size-1) goto w2_exit;    /* quit if overflow screen */
  690. X            wlp[++curr_y]->start = wdot + 1;
  691. X            cr_found = wlp[curr_y]->cflag = 0;        /* init new line */
  692. X            if (curr_x -= 2) w_ebol();        /* back up over ^X; if not at left margin, erase beginning of line */
  693. X            wlp[curr_y]->col = curr_x;                /* save starting column */
  694. X            }
  695. X       noprint:
  696. X        if (++ w_p1.c > CELLSIZE - 1) w_p1.p = w_p1.p->f, w_p1.c = 0;    /* next char in buffer */
  697. X        }        /* end of "for all characters" */
  698. X
  699. X    if (dot == z)
  700. X        {
  701. X        if (curr_x < WN_width) w_makecurs(' ', 1), w_type(' ', 1), vt(VT_CLRSPEC);    /* display a space, unless at end */
  702. X        else curs_crflag = curs_c = 0;                /* else set "no cursor displayed" */
  703. X        }
  704. X
  705. X    /* clear rest of line if needed */
  706. X    if (!cr_found && (redraw_sw || (curr_x < wlp[curr_y]->n)))
  707. X        {
  708. X        wlp[curr_y]->n = curr_x;
  709. X        if (curr_x < WN_width) vtm(VT_EEOL);
  710. X        }
  711. X    wlp[curr_y]->end = wdot;        /* save char at end of last line */
  712. X  w2_exit:
  713. X    last_y = curr_y;                /* record last used line on screen */
  714. X    }
  715. X /* routine to move cursor to current location and then call vt */
  716. X
  717. Xvtm(arg)
  718. X    int arg;
  719. X    {
  720. X    w_move(curr_y, curr_x);
  721. X    vt(arg);
  722. X    }
  723. X
  724. X
  725. X
  726. X
  727. X/* routine to set reverse video and save cursor location */
  728. X/* first argument is char at cursor, 2nd is value for curs_crflag */
  729. X
  730. Xw_makecurs(wc, crflag)
  731. X    char wc;
  732. X    short crflag;
  733. X    {
  734. X    curs_y = curr_y, curs_x = curr_x, curs_c = wc;    /* save cursor coord and char */
  735. X    curs_p = &wlp[curr_y]->ch[curr_x];                /* save location of cursor spot in window image */
  736. X    curs_crflag = crflag;        /* save crflag */
  737. X    vt(VT_SETSPEC2);            /* set flag and reverse video */
  738. X    }
  739. X
  740. X
  741. X
  742. X
  743. X/* routine to handle line overflow */
  744. X/* returns nonzero if at end of screen, zero otherwise */
  745. X/* arg is current character position */
  746. X
  747. Xint w_overflow(wd)
  748. X    {
  749. X    wlp[curr_y]->end = wd-1;            /* last character was end of this line */
  750. X    if (wlp[curr_y]->n > curr_x)
  751. X        {
  752. X        wlp[curr_y]->n = curr_x;
  753. X        if (curr_x < WN_width) vtm(VT_EEOL);        /* if old line was wider, erase */
  754. X        }
  755. X    if (curr_y >= window_size-1) return(1);
  756. X    wlp[curr_y]->cflag |= WF_BEG;                /* mark this line as "continued" */
  757. X    wlp[++curr_y]->cflag = WF_CONT;                /* next line is a continuation line */
  758. X    wlp[curr_y]->start = wd;                    /* char about to be printed is this line's first */
  759. X    wlp[curr_y]->col = curr_x = 0;                /* new line starts at left margin */
  760. X    fputs("\033(0", stdout);                    /* alternate char set */
  761. X    w_type('h', W_MARK);                        /* "NL" space */
  762. X    w_type(' ', W_MARK);
  763. X    fputs("\033(B", stdout);
  764. X    return(0);
  765. X    }
  766. X /* routine to type one character:  arguments are char and a */
  767. X/* "mark" bit.  If mark is set, the char is always retyped  */
  768. X
  769. Xw_type(c, m)
  770. X    char c;
  771. X    int m;
  772. X    {
  773. X    register char *p;
  774. X
  775. X    p = &wlp[curr_y]->ch[curr_x];        /* pointer to char image */
  776. X    if ((c != *p) || (m) || (redraw_sw) || (curr_x >= wlp[curr_y]->n))
  777. X        {
  778. X        w_move(curr_y, curr_x);
  779. X        putchar(c);
  780. X        *p = (m) ? c | W_MARK : c;
  781. X        ++term_x;
  782. X        }
  783. X    ++curr_x;
  784. X    if (wlp[curr_y]->n < curr_x) wlp[curr_y]->n = curr_x;    /* if we've lengthened the line, record that fact */
  785. X    }
  786. X
  787. X
  788. X
  789. X
  790. X/* initialize display image */
  791. X
  792. Xw_init()
  793. X    {
  794. X    short i, j;
  795. X
  796. X    for (i = 0; i < window_size; i++)        /* for each row */
  797. X        {
  798. X        wlp[i] = &w_image[i];                /* set pointer to this line's data */
  799. X        w_image[i].n = w_image[i].cflag = 0;    /* no chars used, cr flag clear */
  800. X        for (j = 0; j < W_MAX_H; w_image[i].ch[j++] = ' ');        /* clear line */
  801. X        }
  802. X    }
  803. X
  804. X
  805. X
  806. X
  807. X/* put character followed by appropriate number of nulls for "other control function" */
  808. X/* if argument is 0, output filler chars only */
  809. X
  810. Xputchar_d(c)
  811. X    char c;
  812. X    {
  813. X    int i;
  814. X
  815. X    if (c) putchar(c);                                                /* output character */
  816. X    for (i = 0; i < win_dlyc[win_speed]; i++) putchar('\0');        /* output filler */
  817. X    }
  818. X /* put out appropriate number of filler chars for display function that scrolls (LF, etc.) */
  819. X
  820. Xscroll_dly()
  821. X    {
  822. X    int i;
  823. X
  824. X    for (i = 0; i < win_dlys[win_speed]; i++) putchar('\0');        /* output filler */
  825. X    }
  826. X
  827. X
  828. X
  829. X/* move terminal cursor to stated y, x position */
  830. X/* uses incremental moves or absolute cursor position, whichever is shorter */
  831. X
  832. Xw_move(y, x)
  833. X    short y, x;
  834. X    {
  835. X    register short i;
  836. X
  837. X    /* if practical, use CR to get to left margin */
  838. X    if ((curr_x == 0) && (term_x != 0)) putchar(CR), term_x = 0;
  839. X    if ((y == term_y) && (term_x < WN_width))        /* if term x is beyond last char, use abs positioning */
  840. X        {
  841. X        if (x == term_x) return;
  842. X        if (x > term_x)
  843. X            {
  844. X            if (x - term_x == 1) fputs("\033[C", stdout);
  845. X            else printf("\033[%dC", x - term_x);
  846. X            }
  847. X        else
  848. X            {
  849. X            if ((i = term_x - x) < 4) for (; i > 0; i--) putchar('\b');    /* use BS */
  850. X            else printf("\033[%dD", term_x - x);        /* use incremental jump */
  851. X            }
  852. X        term_x = x;
  853. X        }
  854. X    else
  855. X        {
  856. X        if ((x == term_x) && (term_x < WN_width))
  857. X            {
  858. X            if (y > term_y)
  859. X                {
  860. X                if ((i = y - term_y) < 4) for (; i >0; i--) putchar(LF);    /* use LF */
  861. X                else printf("\033[%dB", i);        /* use incremental jump */
  862. X                }
  863. X            else if ((i = term_y - y) == 1) fputs("\033[A", stdout);    /* move 1 */
  864. X            else printf("\033[%dA", i);
  865. X            term_y = y;
  866. X            }
  867. X        else printf("\033[%d;%dH", (term_y = y) + 1, (term_x = x) + 1);        /* absolute jump */
  868. X        }
  869. X    }
  870. X /* scroll screen: argument is count: + up, - down */
  871. X
  872. Xw_scroll(count)
  873. X    int count;
  874. X    {
  875. X    register int i, ic;
  876. X    struct w_line *p[W_MAX_V];        /* temp copy of pointer array */
  877. X
  878. X    if (count > 0)        /* scrolling up */
  879. X        {
  880. X        w_move(window_size-1, 0);    /* cursor to bottom of window */
  881. X        for (i = 0; i < count; i++)
  882. X            {
  883. X            putchar(LF), wlp[i]->n = 0;        /* scroll terminal, blank out image line */
  884. X            }
  885. X        }
  886. X    else        /* scroll down */
  887. X        {
  888. X        w_move(0, 0);        /* cursor to top */
  889. X        for (i = 0; i > count; i--)
  890. X            {
  891. X            fputs("\033M", stdout), wlp[window_size-1+i]->n = 0;
  892. X            }
  893. X        }
  894. X    for (i = 0; i < window_size; i++) p[i] = wlp[(window_size + i + count) % window_size];    /* rearrange */
  895. X    for (i = 0; i < window_size; i++) wlp[i] = p[i];
  896. X    }
  897. X
  898. X
  899. X
  900. X/* clear line to left of curr_x */
  901. X/* if some chars nonblank, does erase from start of line */
  902. X
  903. Xw_ebol()
  904. X    {
  905. X    short i, j;
  906. X
  907. X    for (j = i = 0; i < curr_x; i++) if (wlp[curr_y]->ch[i] != ' ') wlp[curr_y]->ch[i] = ' ', j++;
  908. X    if (j || redraw_sw) w_move(curr_y, curr_x-1), vt(VT_EBOL);
  909. X    }
  910. X
  911. X
  912. X
  913. X/* routine to set a pointer to a given location (like set_pointer) */
  914. X/* returns nonzero if a text buffer exists, otherwise 0 */
  915. X
  916. Xint w_setptr(loc, pp)
  917. X    register int loc;                /* location */
  918. X    register struct qp *pp;            /* address of pointer */
  919. X    {
  920. X    register int i;
  921. X
  922. X    if (buff.f)
  923. X        {
  924. X        for (i = loc / CELLSIZE, pp->p = buff.f; i > 0; i--) pp->p = pp->p->f;
  925. X        pp->c = loc % CELLSIZE;
  926. X        pp->dot = loc;
  927. X        }
  928. X    return( (int) buff.f);
  929. X    }
  930. X /* routine to move N lines (back, forward, or 0)                */
  931. X/* w_lines(n, &source, &dest) where n is the line count, source    */
  932. X/* points to a qp at the current pointer, dest, if nonzero,        */
  933. X/* it points to a qp where the result is to go.                    */
  934. X/* routine returns actual number of display lines                */
  935. X
  936. Xstruct qp w_lines_p;                /* to compute # of display lines in -N lines */
  937. X
  938. Xint w_lines(n, ps, pd)
  939. X    int n;                            /* number of lines */
  940. X    register struct qp *ps, *pd;    /* source, destination qp's */
  941. X    {
  942. X    register struct buffcell *tp;    /* local copy of the qp */
  943. X    register int tc, tdot, tn;
  944. X    int tcnt, tl;                    /* chars/line and display line count */
  945. X    char tch;
  946. X
  947. X    tdot = ps->dot;
  948. X    tp = ps->p;
  949. X    tc = ps->c;
  950. X
  951. X    if (n > 0)            /* argument is positive */
  952. X        {
  953. X        for (tcnt = tl = tn = 0; (tn < n) && (tdot < z); tdot++)    /* forward over N line separators */
  954. X            {
  955. X            if (spec_chars[ tch = tp->ch[tc] ] & A_L) ++tl, ++tn;        /* count separators */
  956. X            else if (!(et_val & ET_TRUNC))        /* if text lines can overflow screen lines */
  957. X                {
  958. X                if (!(tch & 0140))                /* if character is a control char */
  959. X                    {
  960. X                    if (tch == CR)                                        /* CR resets count */
  961. X                        {
  962. X                        if (tcnt > WN_width) ++tl;
  963. X                        tcnt = 0;
  964. X                        }
  965. X                    else if (tch == TAB) tcnt = (tcnt | tabmask) +1;    /* tab to next tab stop */
  966. X                    else if (tch == ESC) ++tcnt;                        /* ESC takes one space */
  967. X                    else tcnt += 2;                                        /* normal control chars take 2 spaces */
  968. X                    }
  969. X                else ++tcnt;                /* not a control char: takes one space */
  970. X                if (tcnt > WN_width) ++tl, tcnt = 2;        /* if overflow, one more line */
  971. X                }
  972. X
  973. X            if (++tc > CELLSIZE-1) tp = tp->f, tc = 0;        /* next character position */
  974. X            }
  975. X        if (tl > tn) tn = tl;        /* if counting display lines and there's more of them, return that */
  976. X        }
  977. X     else                /* argument is zero or negative */
  978. X        {
  979. X        for (tn = 0; (tn >= n) && (tdot > 0); )        /* back up over (n+1) line feeds */
  980. X            {
  981. X            --tdot;
  982. X            if (--tc < 0) tp = tp->b, tc = CELLSIZE -1;
  983. X            if (spec_chars[tp->ch[tc]] & A_L) --tn;
  984. X            }
  985. X        if (tn < n)            /* if stopped on a line sep, fwd over it */
  986. X            {
  987. X            ++tn;
  988. X            ++tdot;
  989. X            if (++tc > CELLSIZE-1) tp = tp->f, tc = 0;
  990. X            }
  991. X
  992. X        if (!(et_val & ET_TRUNC) && (n != 0))            /* if text line can overflow display line */
  993. X            {
  994. X            w_lines_p.dot = tdot, w_lines_p.p = tp, w_lines_p.c = tc;        /* then count the number of display */
  995. X            tn = -w_lines(-n, &w_lines_p, 0);                /* lines in the N text lines we just backed up over */
  996. X            }
  997. X        }
  998. X
  999. X    if (pd) pd->dot = tdot, pd->p = tp, pd->c = tc;        /* if an "after" pointer given, update it */
  1000. X    return(tn);
  1001. X    }
  1002. X
  1003. END_OF_te_window.c
  1004. if test 33018 -ne `wc -c <te_window.c`; then
  1005.     echo shar: \"te_window.c\" unpacked with wrong size!?
  1006. fi
  1007. # end of overwriting check
  1008. fi
  1009. echo shar: End of archive 4 \(of 4\).
  1010. cp /dev/null ark4isdone
  1011. DONE=true
  1012. for I in 1 2 3 4 ; do
  1013.     if test ! -f ark${I}isdone ; then
  1014.     echo shar: You still need to run archive ${I}.
  1015.     DONE=false
  1016.     fi
  1017. done
  1018. if test "$DONE" = "true" ; then
  1019.     echo You have unpacked all 4 archives.
  1020.     echo "See the *.doc files"
  1021.     rm -f ark[1-9]isdone
  1022. fi
  1023. ##  End of shell archive.
  1024. exit 0
  1025.